// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

/*
	Package flag implements command-line flag parsing.

	Usage

	Define flags using flag.String(), Bool(), Int(), etc.

	This declares an integer flag, -n, stored in the pointer nFlag, with type *int:
		import "flag"
		var nFlag = flag.Int("n", 1234, "help message for flag n")
	If you like, you can bind the flag to a variable using the Var() functions.
		var flagvar int
		func init() {
			flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
		}
	Or you can create custom flags that satisfy the Value interface (with
	pointer receivers) and couple them to flag parsing by
		flag.Var(&flagVal, "name", "help message for flagname")
	For such flags, the default value is just the initial value of the variable.

	After all flags are defined, call
		flag.Parse()
	to parse the command line into the defined flags.

	Flags may then be used directly. If you're using the flags themselves,
	they are all pointers; if you bind to variables, they're values.
		fmt.Println("ip has value ", *ip)
		fmt.Println("flagvar has value ", flagvar)

	After parsing, the arguments following the flags are available as the
	slice flag.Args() or individually as flag.Arg(i).
	The arguments are indexed from 0 through flag.NArg()-1.

	Command line flag syntax

	The following forms are permitted:

		-flag
		-flag=x
		-flag x  // 非布尔标志仅
	One or two minus signs may be used; they are equivalent.
	The last form is not permitted for boolean flags because the
	meaning of the command
		cmd -x *
	where * is a Unix shell wildcard, will change if there is a file
	called 0, false, etc. You must use the -flag=false form to turn
	off a boolean flag.

	Flag parsing stops just before the first non-flag argument
	("-" is a non-flag argument) or after the terminator "--".

	Integer flags accept 1234, 0664, 0x1234 and may be negative.
	Boolean flags may be:
		1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False
	Duration flags accept any input valid for time.ParseDuration.

	The default set of command-line flags is controlled by
	top-level functions.  The FlagSet type allows one to define
	independent sets of flags, such as to implement subcommands
	in a command-line interface. The methods of FlagSet are
	analogous to the top-level functions for the command-line
	flag set.
*/
package flag

import (
	"errors"
	"fmt"
	"io"
	"os"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"time"
)

// 如果调用-help或-h标志，则返回错误
// 但未定义此类标志。
var ErrHelp = errors.New("flag: help requested")

// 如果一个标志的值无法解析，例如Int的整数无效，则会通过Set返回errParse。
// 然后通过failf包装以提供更多信息。
var errParse = errors.New("parse error")

// 如果标志的值超出范围，则通过设置返回errRange。
// 然后通过failf进行包装，以提供更多信息。
var errRange = errors.New("value out of range")

func numError(err error) error {
	ne, ok := err.(*strconv.NumError)
	if !ok {
		return err
	}
	if ne.Err == strconv.ErrSyntax {
		return errParse
	}
	if ne.Err == strconv.ErrRange {
		return errRange
	}
	return err
}

// /--布尔值
type boolValue bool

func newBoolValue(val bool, p *bool) *boolValue {
	*p = val
	return (*boolValue)(p)
}

func (b *boolValue) Set(s string) error {
	v, err := strconv.ParseBool(s)
	if err != nil {
		err = errParse
	}
	*b = boolValue(v)
	return err
}

func (b *boolValue) Get() any { return bool(*b) }

func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) }

func (b *boolValue) IsBoolFlag() bool { return true }

// 可选接口，用于指示可以是
// 不带“=Value”文本
type boolFlag interface {
	Value
	IsBoolFlag() bool
}

// /--int值
type intValue int

func newIntValue(val int, p *int) *intValue {
	*p = val
	return (*intValue)(p)
}

func (i *intValue) Set(s string) error {
	v, err := strconv.ParseInt(s, 0, strconv.IntSize)
	if err != nil {
		err = numError(err)
	}
	*i = intValue(v)
	return err
}

func (i *intValue) Get() any { return int(*i) }

func (i *intValue) String() string { return strconv.Itoa(int(*i)) }

// /--int64值
type int64Value int64

func newInt64Value(val int64, p *int64) *int64Value {
	*p = val
	return (*int64Value)(p)
}

func (i *int64Value) Set(s string) error {
	v, err := strconv.ParseInt(s, 0, 64)
	if err != nil {
		err = numError(err)
	}
	*i = int64Value(v)
	return err
}

func (i *int64Value) Get() any { return int64(*i) }

func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) }

// /--uint值
type uintValue uint

func newUintValue(val uint, p *uint) *uintValue {
	*p = val
	return (*uintValue)(p)
}

func (i *uintValue) Set(s string) error {
	v, err := strconv.ParseUint(s, 0, strconv.IntSize)
	if err != nil {
		err = numError(err)
	}
	*i = uintValue(v)
	return err
}

func (i *uintValue) Get() any { return uint(*i) }

func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) }

// /--uint64值
type uint64Value uint64

func newUint64Value(val uint64, p *uint64) *uint64Value {
	*p = val
	return (*uint64Value)(p)
}

func (i *uint64Value) Set(s string) error {
	v, err := strconv.ParseUint(s, 0, 64)
	if err != nil {
		err = numError(err)
	}
	*i = uint64Value(v)
	return err
}

func (i *uint64Value) Get() any { return uint64(*i) }

func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) }

// /--字符串值
type stringValue string

func newStringValue(val string, p *string) *stringValue {
	*p = val
	return (*stringValue)(p)
}

func (s *stringValue) Set(val string) error {
	*s = stringValue(val)
	return nil
}

func (s *stringValue) Get() any { return string(*s) }

func (s *stringValue) String() string { return string(*s) }

// /--64值
type float64Value float64

func newFloat64Value(val float64, p *float64) *float64Value {
	*p = val
	return (*float64Value)(p)
}

func (f *float64Value) Set(s string) error {
	v, err := strconv.ParseFloat(s, 64)
	if err != nil {
		err = numError(err)
	}
	*f = float64Value(v)
	return err
}

func (f *float64Value) Get() any { return float64(*f) }

func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) }

// /--时间持续时间值
type durationValue time.Duration

func newDurationValue(val time.Duration, p *time.Duration) *durationValue {
	*p = val
	return (*durationValue)(p)
}

func (d *durationValue) Set(s string) error {
	v, err := time.ParseDuration(s)
	if err != nil {
		err = errParse
	}
	*d = durationValue(v)
	return err
}

func (d *durationValue) Get() any { return time.Duration(*d) }

func (d *durationValue) String() string { return (*time.Duration)(d).String() }

type funcValue func(string) error

func (f funcValue) Set(s string) error { return f(s) }

func (f funcValue) String() string { return "" }

// 值是存储在标志中的动态值的接口。
// /（默认值表示为字符串。）
// 
// 如果一个值的IsBoolFlag（）bool方法返回true，
// 命令行解析器将-name等效于-name=true 
// 而不是使用下一个命令行参数。
// 
// Set按命令行顺序为每个存在的标志调用一次。
// flag包可以使用零值接收器调用String方法，
// 例如nil指针。
type Value interface {
	String() string
	Set(string) error
}

// Getter是一个允许检索值内容的接口。
// 它包装了值接口，而不是它的一部分，因为它出现在Go 1及其兼容规则之后。这个包提供的所有值类型都满足Getter接口，Func使用的类型除外。
type Getter interface {
	Value
	Get() any
}

// ErrorHandling定义了如何设置标记集。如果解析失败，解析将正常运行。
type ErrorHandling int

// 这些常量导致标记集。如果解析失败，Parse将按照所描述的方式进行操作。
const (
	ContinueOnError ErrorHandling = iota // 返回一个描述性错误。
	ExitOnError                          // 呼叫操作系统。退出（2）或-h/-help退出（0）。
	PanicOnError                         // 调用带有描述错误的panic。
)

// 标志集表示一组已定义的标志。标记集
// 的零值没有名称，并且具有持续错误处理。
// 
// 标志名称在标志集中必须是唯一的。试图定义其
// 名称已在使用的标志将导致恐慌。
type FlagSet struct {
	// 用法是在分析标志时发生错误时调用的函数。
	// 该字段是一个函数（不是方法），可以更改为指向自定义错误处理程序
	// 的字段。调用Usage后会发生什么取决于错误处理设置；对于命令行，默认情况下
	// 为ExitOnError，它在调用Usage后退出程序。
	Usage func()

	name          string
	parsed        bool
	actual        map[string]*Flag
	formal        map[string]*Flag
	args          []string // 标志后的参数
	errorHandling ErrorHandling
	output        io.Writer // nil表示stderr；use Output（）访问器
}

// 标志表示标志的状态。
type Flag struct {
	Name     string // 命令行上显示的名称
	Usage    string // 帮助消息
	Value    Value  // 设置值
	DefValue string // 默认值（文本）；对于用法消息
}

// sortFlags，以字典排序顺序将标志作为片段返回。
func sortFlags(flags map[string]*Flag) []*Flag {
	result := make([]*Flag, len(flags))
	i := 0
	for _, f := range flags {
		result[i] = f
		i++
	}
	sort.Slice(result, func(i, j int) bool {
		return result[i].Name < result[j].Name
	})
	return result
}

// 输出返回用法和错误消息的目标。操作系统。如果
// 输出未设置或设置为零，则返回Stderr。
func (f *FlagSet) Output() io.Writer {
	if f.output == nil {
		return os.Stderr
	}
	return f.output
}

// Name返回标志集的名称。
func (f *FlagSet) Name() string {
	return f.name
}

// ErrorHandling返回标志集的错误处理行为。
func (f *FlagSet) ErrorHandling() ErrorHandling {
	return f.errorHandling
}

// SetOutput设置用法和错误消息的目标。wen jian defg
func (f *FlagSet) SetOutput(output io.Writer) {
	f.output = output
}

// VisitAll按字典顺序访问国旗，并为每个国旗调用fn。
// 它访问所有旗帜，即使是未设置的旗帜。
func (f *FlagSet) VisitAll(fn func(*Flag)) {
	for _, flag := range sortFlags(f.formal) {
		fn(flag)
	}
}

// visitoll按字典顺序访问命令行标志，并分别调用
// fn。它访问所有旗帜，甚至那些没有设置。
func VisitAll(fn func(*Flag)) {
	CommandLine.VisitAll(fn)
}

// Visit按字典顺序访问旗帜，为每个旗帜调用fn。
// 它只访问已设置的标志。
func (f *FlagSet) Visit(fn func(*Flag)) {
	for _, flag := range sortFlags(f.actual) {
		fn(flag)
	}
}

// Visit按字典顺序访问命令行标志，为每个标志调用fn 
// 。它只访问已设置的标志。
func Visit(fn func(*Flag)) {
	CommandLine.Visit(fn)
}

// Lookup返回指定标志的标志结构，如果不存在，则返回nil。
func (f *FlagSet) Lookup(name string) *Flag {
	return f.formal[name]
}

// Lookup返回指定命令行标志
// 如果不存在，则返回nil。
func Lookup(name string) *Flag {
	return CommandLine.formal[name]
}

// Set设置命名标志的值。
func (f *FlagSet) Set(name, value string) error {
	flag, ok := f.formal[name]
	if !ok {
		return fmt.Errorf("no such flag -%v", name)
	}
	err := flag.Value.Set(value)
	if err != nil {
		return err
	}
	if f.actual == nil {
		f.actual = make(map[string]*Flag)
	}
	f.actual[name] = flag
	return nil
}

// Set设置命名命令行标志的值。
func Set(name, value string) error {
	return CommandLine.Set(name, value)
}

// isZeroValue确定字符串是否代表标志的零
// 值。
func isZeroValue(flag *Flag, value string) bool {
	// 构建标志值类型的零值，查看调用其String方法的结果是否等于传入的值。
	// 除非值类型本身是接口类型，否则此选项有效。
	typ := reflect.TypeOf(flag.Value)
	var z reflect.Value
	if typ.Kind() == reflect.Pointer {
		z = reflect.New(typ.Elem())
	} else {
		z = reflect.Zero(typ)
	}
	return value == z.Interface().(Value).String()
}

// UnquoteUsage从用法
// 字符串中提取一个带反引号的名称作为标志，并返回它和未带引号的用法。
// 给定“要显示的名称”，它返回（“名称”，“要显示的名称”）。
// 如果没有反引号，则该名称是对标志值的
// 类型的合理猜测，如果标志为布尔值，则为空字符串。
func UnquoteUsage(flag *Flag) (name string, usage string) {
	// 查找后引号的名称，但避免使用strings包。
	usage = flag.Usage
	for i := 0; i < len(usage); i++ {
		if usage[i] == '`' {
			for j := i + 1; j < len(usage); j++ {
				if usage[j] == '`' {
					name = usage[i+1 : j]
					usage = usage[:i] + name + usage[j+1:]
					return name, usage
				}
			}
			break // 只有一个反向报价；使用类型名称。
		}
	}
	// 没有明确的名称，所以如果我们能找到，请使用type。
	name = "value"
	switch flag.Value.(type) {
	case boolFlag:
		name = ""
	case *durationValue:
		name = "duration"
	case *float64Value:
		name = "float"
	case *intValue, *int64Value:
		name = "int"
	case *stringValue:
		name = "string"
	case *uintValue, *uint64Value:
		name = "uint"
	}
	return
}

// PrintDefaults打印集合中所有已定义命令行标志的默认值，除非另有配置，否则将按标准错误打印。有关全局函数PrintDefaults的更多信息，请参阅
// 文档。
func (f *FlagSet) PrintDefaults() {
	f.VisitAll(func(flag *Flag) {
		var b strings.Builder
		fmt.Fprintf(&b, "  -%s", flag.Name) // 前面两个空格-；见下面两条评论。
		name, usage := UnquoteUsage(flag)
		if len(name) > 0 {
			b.WriteString(" ")
			b.WriteString(name)
		}
		// 一个ASCII字母的布尔标志非常常见，我们特别对待它们，把它们的用法放在同一行上。
		if b.Len() <= 4 { // 空格，空格，'-'，'x'。
			b.WriteString("\t")
		} else {
			// 在制表符触发良好对齐之前的四个空格
			// 对于4-空格和8-空格制表符停止。
			b.WriteString("\n    \t")
		}
		b.WriteString(strings.ReplaceAll(usage, "\n", "\n    \t"))

		if !isZeroValue(flag, flag.DefValue) {
			if _, ok := flag.Value.(*stringValue); ok {
				// 在值
				fmt.Fprintf(&b, " (default %q)", flag.DefValue)
			} else {
				fmt.Fprintf(&b, " (default %v)", flag.DefValue)
			}
		}
		fmt.Fprint(f.Output(), b.String(), "\n")
	})
}

// PrintDefaults打印时加引号，除非另有配置，否则为标准错误，
// 一条用法消息，显示所有已定义的
// 命令行标志的默认设置。
// 对于整数值标志x，默认输出的形式为
// /-x int 
// /usage-message-For-x（默认7）
// 除了
// 一个单字节名称的bool标志外，任何东西的使用信息都会显示在单独的一行上。对于bool标志，类型为
// 省略，如果标志名称为一个字节，则用法消息将显示在同一行
// 中。如果
// 默认值是该类型的零值，则省略带括号的默认值。列出的类型，这里是int，
// 可以通过在标志的用法
// 字符串中放置一个后引号的名称来更改；消息中的第一个这样的项被视为要在消息中显示的参数
// 名称，并且在显示消息时，从
// 中去掉反引号。例如，给定
// 标志。字符串（“I”，“search`directory`forinclude files”）
// 输出将是
// /-I directory 
// 搜索include files目录。
// 
// 要更改标志消息的目标，请调用命令行。设置输出。
func PrintDefaults() {
	CommandLine.PrintDefaults()
}

// 默认用法是打印用法消息的默认函数。
func (f *FlagSet) defaultUsage() {
	if f.name == "" {
		fmt.Fprintf(f.Output(), "Usage:\n")
	} else {
		fmt.Fprintf(f.Output(), "Usage of %s:\n", f.name)
	}
	f.PrintDefaults()
}

// 注意：用法不仅仅是defaultUsage（命令行）
// 因为它（通过godoc标志用法）作为示例
// 来说明如何编写自己的用法函数。

// 用法将记录所有已定义命令行标志的用法消息打印到命令行的输出，默认为os。斯特德尔。
// 在分析标志时发生错误时调用它。
// 该函数是一个变量，可以更改为指向自定义函数。
// 默认情况下，它打印一个简单的头并调用PrintDefaults；有关
// 输出格式及其控制方法的详细信息，请参阅PrintDefaults文档。
// 自定义使用函数可以选择退出程序；默认情况下，当命令行的错误处理策略设置为
// 仍然会发生。
// ExitOnError时，退出
var Usage = func() {
	fmt.Fprintf(CommandLine.Output(), "Usage of %s:\n", os.Args[0])
	PrintDefaults()
}

// NFlag返回已设置的标志数。
func (f *FlagSet) NFlag() int { return len(f.actual) }

// NFlag返回已设置的命令行标志数。
func NFlag() int { return len(CommandLine.actual) }

// Arg返回第i个参数。Arg（0）是处理标志后剩余的第一个参数
// 。如果
// 请求的元素不存在，则Arg返回空字符串。
func (f *FlagSet) Arg(i int) string {
	if i < 0 || i >= len(f.args) {
		return ""
	}
	return f.args[i]
}

// Arg返回第i个命令行参数。Arg（0）是处理标志后剩余的第一个参数
// 。如果
// 请求的元素不存在，则Arg返回空字符串。
func Arg(i int) string {
	return CommandLine.Arg(i)
}

// NArg是处理标志后剩余的参数数。
func (f *FlagSet) NArg() int { return len(f.args) }

// NArg是处理标志后剩余的参数数。
func NArg() int { return len(CommandLine.args) }

// Args返回非标志参数。
func (f *FlagSet) Args() []string { return f.args }

// Args返回非标志命令行参数。
func Args() []string { return CommandLine.args }

// BoolVar使用指定的名称、默认值和用法字符串定义bool标志。
// 参数p指向一个bool变量，用于存储标志的值。
func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
	f.Var(newBoolValue(value, p), name, usage)
}

// BoolVar使用指定的名称、默认值和用法字符串定义bool标志。
// 参数p指向一个bool变量，用于存储标志的值。
func BoolVar(p *bool, name string, value bool, usage string) {
	CommandLine.Var(newBoolValue(value, p), name, usage)
}

// Bool使用指定的名称、默认值和用法字符串定义Bool标志。
// 返回值是存储标志值的bool变量的地址。
func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
	p := new(bool)
	f.BoolVar(p, name, value, usage)
	return p
}

// Bool使用指定的名称、默认值和用法字符串定义Bool标志。
// 返回值是存储标志值的bool变量的地址。
func Bool(name string, value bool, usage string) *bool {
	return CommandLine.Bool(name, value, usage)
}

// IntVar使用指定的名称、默认值和用法字符串定义一个int标志。
// 参数p指向一个int变量，用于存储标志的值。
func (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
	f.Var(newIntValue(value, p), name, usage)
}

// IntVar使用指定的名称、默认值和用法字符串定义一个int标志。
// 参数p指向一个int变量，用于存储标志的值。
func IntVar(p *int, name string, value int, usage string) {
	CommandLine.Var(newIntValue(value, p), name, usage)
}

// Int使用指定的名称、默认值和用法字符串定义一个Int标志。
// 返回值是存储标志值的int变量的地址。
func (f *FlagSet) Int(name string, value int, usage string) *int {
	p := new(int)
	f.IntVar(p, name, value, usage)
	return p
}

// Int用指定的名称、默认值和用法字符串定义一个Int标志。
// 返回值是存储标志值的int变量的地址。
func Int(name string, value int, usage string) *int {
	return CommandLine.Int(name, value, usage)
}

// Int64Var使用指定的名称、默认值和用法字符串定义int64标志。
// 参数p指向一个int64变量，用于存储标志的值。
func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) {
	f.Var(newInt64Value(value, p), name, usage)
}

// Int64Var使用指定的名称、默认值和用法字符串定义int64标志。
// 参数p指向一个int64变量，用于存储标志的值。
func Int64Var(p *int64, name string, value int64, usage string) {
	CommandLine.Var(newInt64Value(value, p), name, usage)
}

// Int64使用指定的名称、默认值和用法字符串定义Int64标志。
// 返回值是存储标志值的int64变量的地址。
func (f *FlagSet) Int64(name string, value int64, usage string) *int64 {
	p := new(int64)
	f.Int64Var(p, name, value, usage)
	return p
}

// Int64使用指定的名称、默认值和用法字符串定义Int64标志。
// 返回值是存储标志值的int64变量的地址。
func Int64(name string, value int64, usage string) *int64 {
	return CommandLine.Int64(name, value, usage)
}

// UintVar使用指定的名称、默认值和用法字符串定义uint标志。
// 参数p指向一个uint变量，用于存储标志的值。
func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) {
	f.Var(newUintValue(value, p), name, usage)
}

// UintVar使用指定的名称、默认值和用法字符串定义uint标志。
// 参数p指向一个uint变量，用于存储标志的值。
func UintVar(p *uint, name string, value uint, usage string) {
	CommandLine.Var(newUintValue(value, p), name, usage)
}

// Uint使用指定的名称、默认值和用法字符串定义Uint标志。
// 返回值是存储标志值的uint变量的地址。
func (f *FlagSet) Uint(name string, value uint, usage string) *uint {
	p := new(uint)
	f.UintVar(p, name, value, usage)
	return p
}

// Uint使用指定的名称、默认值和用法字符串定义Uint标志。wen dang
func Uint(name string, value uint, usage string) *uint {
	return CommandLine.Uint(name, value, usage)
}

// Uint64Var使用指定的名称、默认值和用法字符串定义uint64标志。
// 参数p指向一个uint64变量，用于存储标志的值。
func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) {
	f.Var(newUint64Value(value, p), name, usage)
}

// Uint64Var使用指定的名称、默认值和用法字符串定义uint64标志。
// 参数p指向一个uint64变量，用于存储标志的值。
func Uint64Var(p *uint64, name string, value uint64, usage string) {
	CommandLine.Var(newUint64Value(value, p), name, usage)
}

// Uint64使用指定的名称、默认值和用法字符串定义Uint64标志。
// 返回值是存储标志值的uint64变量的地址。
func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 {
	p := new(uint64)
	f.Uint64Var(p, name, value, usage)
	return p
}

// Uint64使用指定的名称、默认值和用法字符串定义Uint64标志。
// 返回值是存储标志值的uint64变量的地址。
func Uint64(name string, value uint64, usage string) *uint64 {
	return CommandLine.Uint64(name, value, usage)
}

// StringVar使用指定的名称、默认值和用法字符串定义字符串标志。
// 参数p指向一个字符串变量，用于存储标志的值。
func (f *FlagSet) StringVar(p *string, name string, value string, usage string) {
	f.Var(newStringValue(value, p), name, usage)
}

// StringVar使用指定的名称、默认值和用法字符串定义字符串标志。
// 参数p指向一个字符串变量，用于存储标志的值。
func StringVar(p *string, name string, value string, usage string) {
	CommandLine.Var(newStringValue(value, p), name, usage)
}

// String使用指定的名称、默认值和用法字符串定义字符串标志。
// 返回值是存储标志值的字符串变量的地址。
func (f *FlagSet) String(name string, value string, usage string) *string {
	p := new(string)
	f.StringVar(p, name, value, usage)
	return p
}

// String使用指定的名称、默认值和用法字符串定义字符串标志。
// 返回值是存储标志值的字符串变量的地址。
func String(name string, value string, usage string) *string {
	return CommandLine.String(name, value, usage)
}

// Float64Var使用指定的名称、默认值和用法字符串定义float64标志。
// 参数p指向一个float64变量，用于存储标志的值。
func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) {
	f.Var(newFloat64Value(value, p), name, usage)
}

// Float64Var使用指定的名称、默认值和用法字符串定义float64标志。
// 参数p指向一个float64变量，用于存储标志的值。
func Float64Var(p *float64, name string, value float64, usage string) {
	CommandLine.Var(newFloat64Value(value, p), name, usage)
}

// Float64使用指定的名称、默认值和用法字符串定义Float64标志。
// 返回值是存储标志值的float64变量的地址。
func (f *FlagSet) Float64(name string, value float64, usage string) *float64 {
	p := new(float64)
	f.Float64Var(p, name, value, usage)
	return p
}

// Float64使用指定的名称、默认值和用法字符串定义Float64标志。
// 返回值是存储标志值的float64变量的地址。
func Float64(name string, value float64, usage string) *float64 {
	return CommandLine.Float64(name, value, usage)
}

// DurationVar定义时间。具有指定名称、默认值和用法字符串的持续时间标志。
// 参数p指向一个时间。用于存储标志值的持续时间变量。
// 该标志接受时间可接受的值。解析持续时间。
func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
	f.Var(newDurationValue(value, p), name, usage)
}

// DurationVar定义时间。使用指定的字符串、名称和持续时间标志。
// 参数p指向一个时间。用于存储标志值的持续时间变量。
// 该标志接受时间可接受的值。解析持续时间。
func DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
	CommandLine.Var(newDurationValue(value, p), name, usage)
}

// 持续时间定义时间。具有指定名称、默认值和用法字符串的持续时间标志。
// 返回值是一个时间的地址。存储标志值的持续时间变量。
// 该标志接受时间可接受的值。解析持续时间。
func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration {
	p := new(time.Duration)
	f.DurationVar(p, name, value, usage)
	return p
}

// 持续时间定义时间。具有指定名称、默认值和用法字符串的持续时间标志。
// 返回值是一个时间的地址。存储标志值的持续时间变量。
// 该标志接受时间可接受的值。解析持续时间。
func Duration(name string, value time.Duration, usage string) *time.Duration {
	return CommandLine.Duration(name, value, usage)
}

// Func使用指定的名称和用法字符串定义标志。
// 每次看到标志时，都会用标志的值调用fn。
// 如果fn返回非nil错误，将被视为标志值解析错误。
func (f *FlagSet) Func(name, usage string, fn func(string) error) {
	f.Var(funcValue(fn), name, usage)
}

// Func使用指定的名称和用法字符串定义标志。
// 每次看到标志时，都会用标志的值调用fn。
// 如果fn返回非nil错误，将被视为标志值解析错误。
func Func(name, usage string, fn func(string) error) {
	CommandLine.Func(name, usage, fn)
}

// Var用指定的名称和用法字符串定义一个标志。标志的type和
// 值由type value的第一个参数表示，
// 通常包含用户定义的value实现。例如，
// 调用者可以创建一个标志，通过向片段提供值的方法，将逗号分隔的字符串转换为字符串的片段
// ；特别是，Set将
// 将逗号分隔的字符串分解为切片。
func (f *FlagSet) Var(value Value, name string, usage string) {
	// 标志不能以“-”开头或包含“=”。
	if strings.HasPrefix(name, "-") {
		panic(f.sprintf("flag %q begins with -", name))
	} else if strings.Contains(name, "=") {
		panic(f.sprintf("flag %q contains =", name))
	}

	// 记住默认值作为字符串；它不会改变。
	flag := &Flag{name, usage, value, value.String()}
	_, alreadythere := f.formal[name]
	if alreadythere {
		var msg string
		if f.name == "" {
			msg = f.sprintf("flag redefined: %s", name)
		} else {
			msg = f.sprintf("%s flag redefined: %s", f.name, name)
		}
		panic(msg) // 仅当使用相同名称声明标志时才会发生
	}
	if f.formal == nil {
		f.formal = make(map[string]*Flag)
	}
	f.formal[name] = flag
}

// Var使用指定的名称和用法字符串定义标志。标志的type和
// 值由type value的第一个参数表示，
// 通常包含用户定义的value实现。例如，
// 调用者可以创建一个标志，通过向片段提供值的方法，将逗号分隔的字符串转换为字符串的片段
// ；特别是，Set将
// 将逗号分隔的字符串分解为切片。
func Var(value Value, name string, usage string) {
	CommandLine.Var(value, name, usage)
}

// sprintf格式化消息，将其打印到输出，然后返回。
func (f *FlagSet) sprintf(format string, a ...any) string {
	msg := fmt.Sprintf(format, a...)
	fmt.Fprintln(f.Output(), msg)
	return msg
}

// failf将格式化错误和用法消息打印到标准错误，
// 返回错误。
func (f *FlagSet) failf(format string, a ...any) error {
	msg := f.sprintf(format, a...)
	f.usage()
	return errors.New(msg)
}

// 用法调用标志集的用法方法（如果指定了），否则调用相应的默认用法函数。
func (f *FlagSet) usage() {
	if f.Usage == nil {
		f.defaultUsage()
	} else {
		f.Usage()
	}
}

// parseOne解析一个标志。它会报告是否看到国旗。
func (f *FlagSet) parseOne() (bool, error) {
	if len(f.args) == 0 {
		return false, nil
	}
	s := f.args[0]
	if len(s) < 2 || s[0] != '-' {
		return false, nil
	}
	numMinuses := 1
	if s[1] == '-' {
		numMinuses++
		if len(s) == 2 { // “--”终止标志
			f.args = f.args[1:]
			return false, nil
		}
	}
	name := s[numMinuses:]
	if len(name) == 0 || name[0] == '-' || name[0] == '=' {
		return false, f.failf("bad flag syntax: %s", s)
	}

	// /这是一个标志。有争论吗？
	f.args = f.args[1:]
	hasValue := false
	value := ""
	for i := 1; i < len(name); i++ { // equals不能是第一个
		if name[i] == '=' {
			value = name[i+1:]
			hasValue = true
			name = name[0:i]
			break
		}
	}
	m := f.formal
	flag, alreadythere := m[name] // BUG 
	if !alreadythere {
		if name == "help" || name == "h" { // nice帮助消息的特殊情况。
			f.usage()
			return false, ErrHelp
		}
		return false, f.failf("flag provided but not defined: -%s", name)
	}

	if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // 特殊情况：不需要arg 
		if hasValue {
			if err := fv.Set(value); err != nil {
				return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err)
			}
		} else {
			if err := fv.Set("true"); err != nil {
				return false, f.failf("invalid boolean flag %s: %v", name, err)
			}
		}
	} else {
		// 它必须有一个值，这可能是下一个参数。
		if !hasValue && len(f.args) > 0 {
			// 值是下一个参数
			hasValue = true
			value, f.args = f.args[0], f.args[1:]
		}
		if !hasValue {
			return false, f.failf("flag needs an argument: -%s", name)
		}
		if err := flag.Value.Set(value); err != nil {
			return false, f.failf("invalid value %q for flag -%s: %v", value, name, err)
		}
	}
	if f.actual == nil {
		f.actual = make(map[string]*Flag)
	}
	f.actual[name] = flag
	return true, nil
}

// Parse解析参数列表中的标志定义，参数列表中不应包含命令名。必须在定义了标志集
// 中的所有标志之后，以及在程序访问标志之前调用。
// 如果设置了-help或-h但未定义，则返回值将为ErrHelp。
func (f *FlagSet) Parse(arguments []string) error {
	f.parsed = true
	f.args = arguments
	for {
		seen, err := f.parseOne()
		if seen {
			continue
		}
		if err == nil {
			break
		}
		switch f.errorHandling {
		case ContinueOnError:
			return err
		case ExitOnError:
			if err == ErrHelp {
				os.Exit(0)
			}
			os.Exit(2)
		case PanicOnError:
			panic(err)
		}
	}
	return nil
}

// Parsed报告是否调用了f.Parse。
func (f *FlagSet) Parsed() bool {
	return f.parsed
}

// Parse解析操作系统中的命令行标志。Args[1:]。必须在定义了所有标志之后，在程序访问标志之前调用
// 。
func Parse() {
	// 忽略错误；命令行设置为ExitOnError。
	CommandLine.Parse(os.Args[1:])
}

// Parsed报告命令行标志是否已被解析。
func Parsed() bool {
	return CommandLine.Parsed()
}

// CommandLine是从操作系统解析的默认命令行标志集。阿格斯。
// BoolVar、Arg等顶级函数是命令行的
// 方法的包装。
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)

func init() {
	// 通过调用全局用法覆盖通用标志集默认用法。
	// 注意：这不是命令行。Usage=Usage，
	// 因为我们希望任何最终调用使用任何更新的Usage值，
	// 而不是运行此行时的值。
	CommandLine.Usage = commandLineUsage
}

func commandLineUsage() {
	Usage()
}

// NewFlagSet返回一个新的空标志集，该标志集具有指定的名称和
// 错误处理属性。如果名称不为空，则会在默认用法消息和错误消息中打印为
// 。
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
	f := &FlagSet{
		name:          name,
		errorHandling: errorHandling,
	}
	f.Usage = f.defaultUsage
	return f
}

// Init为标志集设置名称和错误处理属性。
// 默认情况下，zero标志集使用空名称，而
// ContinueOn错误处理策略。
func (f *FlagSet) Init(name string, errorHandling ErrorHandling) {
	f.name = name
	f.errorHandling = errorHandling
}
